package com.ihr360.payroll.service.salaryprofile.impl;

import com.google.common.collect.Lists;
import com.ihr360.alps.PropertyDescriptor;
import com.ihr360.alps.PropertyType;
import com.ihr360.alps.ServiceDescriptor;
import com.ihr360.alps.api.ServiceProvider;
import com.ihr360.commons.context.session.Ihr360SessionContextHolder;
import com.ihr360.commons.exception.Ihr360RuntimeException;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.vo.ResultInfo;
import com.ihr360.expr.parser.ExprToken;
import com.ihr360.payroll.dao.CompanySalaryProfileRepository;
import com.ihr360.payroll.dao.PayrollConfigRepository;
import com.ihr360.payroll.dao.SystemSalaryFieldRepository;
import com.ihr360.payroll.entity.staff.CompanySalaryProfileEntity;
import com.ihr360.payroll.entity.staff.SalaryProfileFieldEntity;
import com.ihr360.payroll.model.dto.salary.meta.system.SystemSalaryField;
import com.ihr360.payroll.model.dto.salary.profile.CompanySalaryProfile;
import com.ihr360.payroll.model.dto.staff.SalaryProfileField;
import com.ihr360.payroll.service.salaryprofile.CompanySalaryProfileService;
import com.ihr360.payroll.service.salaryprofile.SalaryProfileFieldService;
import com.ihr360.payroll.service.salaryprofile.convertor.CompanySalaryProfileConvertor;
import com.ihr360.rest.reposity.SimpleRestReposity;
import com.ihr360.rest.service.AbstractSimpleRestServiceImpl;
import com.ihr360.shared.basicstaffinfo.dao.SyncedStaffInfoRepository;
import com.ihr360.validation.ValidationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author richey
 */
@Service
public class CompanySalaryProfileServiceImpl extends AbstractSimpleRestServiceImpl<CompanySalaryProfile, Long> implements CompanySalaryProfileService {
    final Logger logger = LoggerFactory.getLogger(getClass());
    private static final String BASESALARY = "basesalary";

    @Autowired
    private CompanySalaryProfileRepository companySalaryProfileRepository;

    @Autowired
    private SystemSalaryFieldRepository systemSalaryFieldRepository;

    @Autowired
    private SalaryProfileFieldService salaryProfileFieldService;

    @Autowired
    private SyncedStaffInfoRepository syncedStaffInfoRepository;

    @Autowired
    private CompanySalaryProfileConvertor companySalaryProfileConvertor;

    @Autowired
    private PayrollConfigRepository payrollConfigRepository;


    @Override
    public SimpleRestReposity<CompanySalaryProfile, Long> getSimpleRestReposity() {
        return companySalaryProfileRepository;
    }

 /*   @Override
    public Boolean deleteProfileFieldByCode(String code) {
        String companyId = Ihr360SessionContextHolder.getCompanyId();
        CompanySalaryProfile companySalaryProfile = companySalaryProfileRepository.findByCompanyId(companyId);
        ValidationUtils.rejectIfEmpty(companySalaryProfile,null,"当前公司不存在薪资档案");
        Long id = companySalaryProfile.getId();
        return salaryProfileFieldRepository.deleteByCodeAndCompanySalaryProfileId(code, id);
    }*/

    // todo indexno 处理
    @Override
    public Boolean addProfileField(String code) {
        if (StringUtils.isEmpty(code)) {
            throw new Ihr360RuntimeException("系统薪资字段元数据code不能为空");
        }
        SystemSalaryField systemSalaryField = systemSalaryFieldRepository.findByCode(code);
        ValidationUtils.rejectIfEmpty(systemSalaryField, null, "根据code未能找到相关系统薪资元字段");
        String companyId = Ihr360SessionContextHolder.getCompanyId();
        CompanySalaryProfile companySalaryProfile = getCompanySalaryProfile(companyId);
        if (companySalaryProfile == null) {
            companySalaryProfile = new CompanySalaryProfile();
            companySalaryProfile = companySalaryProfileRepository.save(companySalaryProfile);
        }
        List<SalaryProfileField> salaryProfileFields = companySalaryProfile.getProfileFields();
        if (salaryProfileFields == null) {
            salaryProfileFields = Lists.newArrayList();
            companySalaryProfile.setProfileFields(salaryProfileFields);
        }
        SalaryProfileField salaryProfileField = new SalaryProfileField();
        BeanUtils.copyProperties(systemSalaryField, salaryProfileField, "id");
        salaryProfileField.setType(systemSalaryField.getType());
        salaryProfileField.setCompanyId(companyId);
        salaryProfileFields.add(salaryProfileField);
        companySalaryProfileRepository.save(companySalaryProfile);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultInfo initCompanySalaryProfile(String companyId) {
        if (StringUtils.isEmpty(companyId)) {
            return new ResultInfo.Builder().error("公司Id不能为空！");
        }
        CompanySalaryProfile companySalaryProfile = companySalaryProfileRepository.findByCompanyId(companyId);
        if (companySalaryProfile != null) {
            return new ResultInfo.Builder().error("公司已存在薪资档案，不需要初始化！");
        }
        companySalaryProfile = new CompanySalaryProfile();
        companySalaryProfile.setCompanyId(companyId);

        List<SalaryProfileField> profileFields = salaryProfileFieldService.getCompanyInitProfileFields();
        if (CollectionUtils.isNotEmpty(profileFields)) {
            profileFields.forEach(f -> f.setCompanyId(companyId));
            companySalaryProfile.setProfileFields(profileFields);
        }
        companySalaryProfileRepository.save(companySalaryProfile);
        return new ResultInfo.Builder().success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultInfo batchInitCompanySalaryProfile() {

        //已经存在薪资方案的公司
        List<String> exitCompanyIds = companySalaryProfileRepository.getAllExitCompanyIds();

        //所有公司
        List<String> toInitCompanyIds = syncedStaffInfoRepository.findAllCompanyIdsExclude(exitCompanyIds);
        List<CompanySalaryProfile> toSave = Lists.newArrayListWithCapacity(toInitCompanyIds.size());

        SystemSalaryField systemSalaryField = systemSalaryFieldRepository.findByCode(BASESALARY);

        toInitCompanyIds.forEach(companyId -> {
            CompanySalaryProfile companySalaryProfile = initCompanySalaryProfile(systemSalaryField, companyId);
            toSave.add(companySalaryProfile);
        });
        companySalaryProfileRepository.save(toSave);
        return new ResultInfo.Builder().success();
    }

    private CompanySalaryProfile initCompanySalaryProfile(SystemSalaryField systemSalaryField, String companyId) {
        CompanySalaryProfile companySalaryProfile = new CompanySalaryProfile();
        companySalaryProfile.setCompanyId(companyId);
        companySalaryProfile.setCreatedAt(new Date());
        List<SalaryProfileField> profileFields = Lists.newArrayList();
        companySalaryProfile.setProfileFields(profileFields);
        SalaryProfileField salaryProfileField = new SalaryProfileField();
        salaryProfileField.setCompanyId(companyId);
        salaryProfileField.setType(systemSalaryField.getType());
        salaryProfileField.setCode(systemSalaryField.getCode());
        salaryProfileField.setCreatedAt(new Date());
        profileFields.add(salaryProfileField);
        companySalaryProfile.setCompanyId(companyId);
        return companySalaryProfile;
    }

    @Override
    public CompanySalaryProfileEntity getByCompanyId(String companyId) {
        CompanySalaryProfile companySalaryProfile = getCompanySalaryProfile(companyId);
        CompanySalaryProfileEntity companySalaryProfileEntity = companySalaryProfileConvertor.convertDtoToEntity(companySalaryProfile);
        List<SalaryProfileFieldEntity> profileFields = companySalaryProfileEntity.getProfileFields();
        if (CollectionUtils.isEmpty(profileFields)) {
            return companySalaryProfileConvertor.convertDtoToEntity(companySalaryProfile);
        }

        Set<String> fieldCodes = profileFields.stream().map(SalaryProfileFieldEntity::getCode).collect(Collectors.toSet());
        List<SystemSalaryField> systemSalaryFields = systemSalaryFieldRepository.findByCodeIn(Lists.newArrayList(fieldCodes));
        ValidationUtils.rejectIfEmpty(systemSalaryFields, null, "数据异常，薪资字段不存在！");
        Map<String, String> systemSalaryFieldMap = systemSalaryFields.stream().collect(Collectors.toMap(SystemSalaryField::getCode, SystemSalaryField::getName));
        profileFields.forEach(profileField -> {
            String fieldName = systemSalaryFieldMap.get(profileField.getCode());
            if (StringUtils.isNotEmpty(fieldName)) {
                profileField.setName(fieldName);
            }
            profileField.setCompanyReferenceFormula(String.join("", ExprToken.EQUAL.val, ServiceProvider.SERVICE_ID.STAFF_SALARY, ExprToken.NS_FIELD_CONNECTOR.val, profileField.getCode()));
        });
        return companySalaryProfileEntity;
    }


    @Override
    public CompanySalaryProfile getOrCreateByCompanyId() {
        String companyId = Ihr360SessionContextHolder.getCompanyId();
        return getCompanySalaryProfile(companyId);
    }

    @Override
    public CompanySalaryProfile getOrCreateByCompanyId(String companyId) {
        return getCompanySalaryProfile(companyId);
    }


    @Override
    public ServiceDescriptor serviceDescriptor(String companyId) {

        CompanySalaryProfileEntity companySalaryProfile = getByCompanyId(companyId);

        if (companySalaryProfile == null) {
            return new ServiceDescriptor();
        }
        List<SalaryProfileFieldEntity> salaryProfileFields = companySalaryProfile.getProfileFields();
        if (CollectionUtils.isEmpty(salaryProfileFields)) {
            return new ServiceDescriptor();
        }

        List<PropertyDescriptor> propertyDescriptors = Lists.newArrayListWithCapacity(salaryProfileFields.size());
        salaryProfileFields.forEach(salaryProfileField -> {
            propertyDescriptors.add(PropertyDescriptor.builder()
                    .id(salaryProfileField.getCode())
                    .name(salaryProfileField.getName())
                    .type(PropertyType.String)
                    .build());
        });
        return ServiceDescriptor.builder()
                .serviceId(ServiceProvider.SERVICE_ID.STAFF_SALARY)
                .name("员工薪资")
                .path("/alps/" + ServiceProvider.SERVICE_ID.STAFF_SALARY)
                .descriptors(propertyDescriptors)
                .build();
    }


    public CompanySalaryProfile getCompanySalaryProfile(String companyId) {
        CompanySalaryProfile companySalaryProfile = companySalaryProfileRepository.findByCompanyId(companyId);
        if (companySalaryProfile == null) {
            SystemSalaryField systemSalaryField = systemSalaryFieldRepository.findByCode(BASESALARY);
            companySalaryProfile = initCompanySalaryProfile(systemSalaryField, companyId);
            companySalaryProfile = companySalaryProfileRepository.save(companySalaryProfile);
        }
        return companySalaryProfile;
    }

}
